﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;

using Microsoft.Crm.Sdk.Messages;

using System.ServiceModel;
using HC.Int.Front2GoCityAccess.WsFront2Go;
using HC.Int.Front2GoCityAccess.WsCityAccess;


/// <summary>
/// Autor: Julio Esquivel 
/// Fecha Junio 2014
/// Descripción: Funciones API CRM y Particulares del Flujo de HC
/// </summary>
/// 
namespace HC.Int.Front2GoCityAccess
{
    public class MetodosFes
    {
        public static IOrganizationService Servicio;

        // Constructor que recibe los parámetros usados para autenticar el Plugin o la Aplicacion Tercera
        public MetodosFes(IOrganizationService serv)
        {
            Servicio = serv;
        }

        #region # Método utilizado para conocer si el atributo se encuentra en el diccionario de datos
        public static Boolean ExisteAtributo(string name, Entity entity)
        {
            Boolean existe = false;
            foreach (var EntidadRes in entity.Attributes)
            {
                if (EntidadRes.Key == name) { existe = true; }
            }
            return existe;
        }
        #endregion

        #region # Método de Recuperación de Metadatos para Opciones de Lista
        public static string RecuperaOpcionListaTexto(string vEntityLogicalName, string vLogicalNameAtributo, OptionSetValue ValorDeComparacion)
        {
            string sReturn = string.Empty;
            string OptionText = "";
            RetrieveAttributeRequest request = new RetrieveAttributeRequest();
            request.EntityLogicalName = vEntityLogicalName;// "";
            request.LogicalName = vLogicalNameAtributo;
            RetrieveAttributeResponse response = (RetrieveAttributeResponse)Servicio.Execute(request);

            PicklistAttributeMetadata picklist = (PicklistAttributeMetadata)response.AttributeMetadata;

            foreach (OptionMetadata option in picklist.OptionSet.Options)
            {
                if (option.Value == ValorDeComparacion.Value)
                {
                    OptionText = option.Label.UserLocalizedLabel.Label;
                    break;
                }
            }
            return sReturn = OptionText;
        }
        #endregion

        #region # Método para Desactivar Registros en CRM
        public static void DesactivarRegistro(bool Desac, string nombreent, Guid Idreg, Int32 Razon)
        {
            var cols = new ColumnSet(new[] { "statecode", "statuscode" });

            //Se verifica si está activo
            var ResEnt = Servicio.Retrieve(nombreent, Idreg, cols);

            if (ResEnt != null)
            {
                //StateCode = 0 Activo
                //StateCode = 1 Inactivo
                SetStateRequest setStateRequest = new SetStateRequest();

                setStateRequest.EntityMoniker = new EntityReference(nombreent, Idreg);

                if (Desac) // Desactivar
                    setStateRequest.State = new OptionSetValue(1);
                else      // Activar
                    setStateRequest.State = new OptionSetValue(0);

                // Colocar la razon para el estado
                setStateRequest.Status = new OptionSetValue(Razon);

                Servicio.Execute(setStateRequest);
            }
        }
        #endregion

        # region # Método de Recuperación de datos en CRM 1 Filtro (Equal)
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1)
        {
            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);


            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }

        #endregion

        # region # Método de Recuperación de datos en CRM 2 filtros (AND) (Equal)
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2)
        {
            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 3 Filtros (AND) (Equal)
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2, string AtributoFiltro3, string ValorFiltro3)
        {
            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);

            FilterExpression filtrosubhijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro3, ConditionOperator.Equal, ValorFiltro3);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 4 Filtros (AND) (Equal)
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2, string AtributoFiltro3, string ValorFiltro3, string AtributoFiltro4, string ValorFiltro4)
        {
            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);
            filtrohijo.AddCondition(AtributoFiltro3, ConditionOperator.Equal, ValorFiltro3);
            filtrohijo.AddCondition(AtributoFiltro4, ConditionOperator.Equal, ValorFiltro4);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 2 filtros (AND) (Equal) Order By Atributo Ascending
        public static EntityCollection RecuperacionMultiple(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2, string AtriOrd)
        {

            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);

            // Orden por el Atributo Recibido
            consulta.AddOrder(AtriOrd, OrderType.Descending);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 2 filtros  (Equal) (AND) (NotEqual)
        public static EntityCollection RecuperacionMultipleNot(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2)
        {

            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.NotEqual, ValorFiltro2);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        # region # Método de Recuperación de datos en CRM 3 filtros  (Equal) (AND) (NotEqual)
        public static EntityCollection RecuperacionMultipleNot(string Entidad, string[] Columnas, string AtributoFiltro1, string ValorFiltro1, string AtributoFiltro2, string ValorFiltro2, string AtributoFiltro3, string ValorFiltro3)
        {

            // Se especifica el nombre de la entidad de dónde se obtendrán los datos (FROM)
            QueryExpression consulta = new QueryExpression(Entidad);

            // Campos a recuperar de la tabla (SELECT)
            consulta.ColumnSet.AddColumns(Columnas);

            // Filtro 1 y 2 como condición en la consulta (WHERE)
            consulta.Criteria = new FilterExpression();
            consulta.Criteria.AddCondition(AtributoFiltro1, ConditionOperator.Equal, ValorFiltro1);

            FilterExpression filtrohijo = consulta.Criteria.AddFilter(LogicalOperator.And);
            filtrohijo.AddCondition(AtributoFiltro2, ConditionOperator.Equal, ValorFiltro2);
            filtrohijo.AddCondition(AtributoFiltro3, ConditionOperator.NotEqual, ValorFiltro3);

            // Se guarda el resultado en una colección de datos
            EntityCollection Registros = Servicio.RetrieveMultiple(consulta);

            return Registros;

        }
        #endregion

        #region # *** Método para encontrar Clave de País, de acuerdo al GUID proporcionado
        public static string DevuelveNombre(string Cad)
        {
            string Nombre = string.Empty;

            if (Cad != string.Empty)
            {
                if (Cad.IndexOf('\\') > 0)
                {
                    var CadSplit = Cad.Split('\\');
                    if (CadSplit.Length.Equals(2))
                        Nombre = CadSplit[1];
                }
            }
            return Nombre;
        }
        #endregion

        #region # *** Método para Encontrar código de País en base al Guid proporcionado
        public static string RecuperaClavePais(Guid IdPais)
        {
            string ClavePais = string.Empty;

            if (IdPais != Guid.Empty)
            {
                Entity Pais = Servicio.Retrieve("new_pais", IdPais, new ColumnSet("new_codigopais_f2g"));
                if (ExisteAtributo("new_codigopais_f2g", Pais))
                    ClavePais = (string)Pais.Attributes["new_codigopais_f2g"];
            }
            return ClavePais;
        }
        #endregion

        #region Metodo Recupera valor DESCRIPTION de campo tipo OptionSetValue
        /// <summary>
        ///  Metodo que devuelve la Description del OptionSet en base al código del dato proveniente
        ///  de las tablas intermedias.
        ///  Parámetros 
        /// <param name="Entidad">Nombre de la entidad de donde se encuentra el OptionSet.</param>   
        /// <param name="sNombreLogico">Nombre lógico del OptionSet.</param>  
        /// <param name="sValue">Código del catalogo correspondiente al OptionSet.</param>   
        /// </summary>
        public static string RecuperaDescripcionOs(string Entidad, string CampoCrm, int Valor)
        {
            string ValorDescripcion = string.Empty;

            RetrieveAttributeRequest retrieveAttributeRequest = new RetrieveAttributeRequest
            {
                EntityLogicalName = Entidad,
                LogicalName = CampoCrm,
                RetrieveAsIfPublished = true
            };

            // Ejecutar la peticion         
            RetrieveAttributeResponse retrieveAttributeResponse = (RetrieveAttributeResponse)Servicio.Execute(retrieveAttributeRequest);
            // Accesando a la información del PickList              
            PicklistAttributeMetadata retrievedPicklistAttributeMetadata = (PicklistAttributeMetadata)retrieveAttributeResponse.AttributeMetadata;
            OptionMetadata[] Opcionlista = retrievedPicklistAttributeMetadata.OptionSet.Options.ToArray();

            foreach (OptionMetadata Metadato in Opcionlista)
            {
                if (Metadato != null)
                    if (Valor == Metadato.Value.Value)
                        ValorDescripcion = Metadato.Description.UserLocalizedLabel.Label.ToString();
            }

            return ValorDescripcion;
        }
        #endregion

        #region  ***  Método para traducir código de error 
        public static string DetalleError(int Cod, int Metodo)
        {
            string Detalle = string.Empty;

            // Hacemos la consulta que filtra por código de error y método 
            EntityCollection Resp = RecuperacionMultiple("new_caterrores_integracion", new string[] { "new_error" }, "new_codigo", Cod.ToString(), "new_integracion", Metodo.ToString(), "statecode", "Active");

            if (Resp.Entities.Count > 0)
            {
                foreach (Entity CatErr in Resp.Entities)
                {
                    if (MetodosFes.ExisteAtributo("new_error", CatErr))
                        Detalle = (string)CatErr.Attributes["new_error"];
                }               
            }
            return Detalle;
        }

        #endregion

        #region Método para Generar RollBack en F2G de Inserción de empresa
        public static bool EliminaF2GCompy(int Sello, string Comp_code, string NomUsr, Guid IdContacto, ws_PerfilesSoapClient Cliente_F2G_R)
        {
            string Respuesta_Del = string.Empty;

            Guid Prop = Guid.Empty;
            bool RespOk = false;

            if (IdContacto != Guid.Empty)
            {
                Entity Contacto = Servicio.Retrieve("contact", IdContacto, new ColumnSet("parentcustomerid"));
                // Recuperamos la empresa que trae el contacto
                if (MetodosFes.ExisteAtributo("parentcustomerid", Contacto))
                {
                    Guid EmpId = ((EntityReference)Contacto.Attributes["parentcustomerid"]).Id;
                    //NomEntidad = ((EntityReference)Cont.Attributes["parentcustomerid"]).Name;

                     // Si existe, entonces recuperamos el código Sello que proporcionó F2G
                    if (EmpId != Guid.Empty)
                    {
                        Entity Empresa = Servicio.Retrieve("account", EmpId, new ColumnSet("new_resp_ftg_ins_cmp", "accountnumber"));

                        // Si existe, se reemplaza el código sello por el que tiene la empresa
                        if (MetodosFes.ExisteAtributo("new_resp_ftg_ins_cmp", Empresa))
                            Sello = (int)Empresa.Attributes["new_resp_ftg_ins_cmp"];

                        // Si existe, se reemplaza el código de compañia por el que tiene la empresa
                        if (MetodosFes.ExisteAtributo("accountnumber", Empresa))
                            Comp_code = (string)Empresa.Attributes["accountnumber"];
                    }
                }
            }

            //// Configuramos Binding de Servicios
            //BasicHttpBinding Front2Go_bin = new BasicHttpBinding();
            //Front2Go_bin.Name = "ws_PerfilesSoap";
            //EndpointAddress EndPointFront2Go = new EndpointAddress("http://172.20.37.175/whsEngine/ws_Perfiles.asmx");

            //// Instanciamos el objeto de los servicios                                    
            //ws_PerfilesSoapClient Cliente_F2G_R = new ws_PerfilesSoapClient(Front2Go_bin, EndPointFront2Go);

            if (Sello > 0 && Comp_code != string.Empty && NomUsr != string.Empty)
            {
                try
                {
                    //Respuesta_Del = Cliente_F2G_R.DeleteCompById(Sello, Comp_code, NomUsr);  /*11 Agosto Se coloca rrivero rigido para borrado (administrador)*/
                    Respuesta_Del = Cliente_F2G_R.DeleteCompById(Sello, Comp_code, "rrivero");
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException("Front2Go DeleteCompById. Error al consumir el método. Detalle: " + ex.Message);
                }

                if (Respuesta_Del.Equals("0"))
                    RespOk = true;
            }

            return RespOk;
        }
        #endregion

        #region Método para Generar RollBack en F2G de Inserción de Contacto
        public static bool EliminaF2GGuest(int Sello, string Mail, string NomUsr, ws_PerfilesSoapClient Cliente_F2G_R)
        {
            string Respuesta_Del = string.Empty;
            bool RespOk = false;

            //// Configuramos Binding de Servicios
            //BasicHttpBinding Front2Go_bin = new BasicHttpBinding();
            //Front2Go_bin.Name = "ws_PerfilesSoap";
            //EndpointAddress EndPointFront2Go = new EndpointAddress("http://172.20.37.175/whsEngine/ws_Perfiles.asmx");

            //// Instanciamos el objeto de los servicios                                    
            //ws_PerfilesSoapClient Cliente_F2G_R = new ws_PerfilesSoapClient(Front2Go_bin, EndPointFront2Go);

            if (Sello > 0 && Mail != string.Empty && NomUsr != string.Empty)
            {
                try
                {
                    //Respuesta_Del = Cliente_F2G_R.DeletePersonById(Sello, Mail, NomUsr); /* 11 Agosto 2014 Se coloca rrivero rigido para borrado (administrador) */
                    Respuesta_Del = Cliente_F2G_R.DeletePersonById(Sello, Mail, "rrivero");
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException("Front2Go DeletePersonById. Error al consumir el método. Detalle: " + ex.Message);
                }

                if (Respuesta_Del.Equals("0"))
                    RespOk = true;
            }

            return RespOk;
        }
        #endregion

        #region Método para Generar RollBack en CA de Inserción de empresa
        public static bool EliminaCityAccCompy(string CodComp, Guid IdContacto,CityAccessWSSoapClient Cliente_CityAcc)
        {
            Resultado Respuesta_Del = null;
            bool RespOk = false;

            //BasicHttpBinding CityAccess_bin = new BasicHttpBinding();
            //CityAccess_bin.Name = "CityAccessWSSoap";
            //EndpointAddress EndPointCityAccess = new EndpointAddress("http://wshc.hotelescity.com:9742/CityHubV28Pruebas/CityAccessWS.asmx");

            //CityAccessWSSoapClient Cliente_CityAcc = new CityAccessWSSoapClient(CityAccess_bin, EndPointCityAccess);

            if (IdContacto != Guid.Empty)
            {
                Entity Contacto = Servicio.Retrieve("contact", IdContacto, new ColumnSet("parentcustomerid"));
                // Recuperamos la empresa que trae el contacto
                if (MetodosFes.ExisteAtributo("parentcustomerid", Contacto))
                {
                    Guid EmpId = ((EntityReference)Contacto.Attributes["parentcustomerid"]).Id;
                    //NomEntidad = ((EntityReference)Cont.Attributes["parentcustomerid"]).Name;

                    // Si existe, entonces recuperamos el código Sello que proporcionó F2G
                    if (EmpId != Guid.Empty)
                    {
                        Entity Empresa = Servicio.Retrieve("account", EmpId, new ColumnSet("accountnumber"));
                     
                        // Si existe, se reemplaza el código de compañia por el que tiene la empresa
                        if (MetodosFes.ExisteAtributo("accountnumber", Empresa))
                            CodComp = (string)Empresa.Attributes["accountnumber"];
                    }
                }
            }

            if (CodComp != string.Empty)
            {
                try
                {
                    Respuesta_Del = Cliente_CityAcc.Delete_Company(CodComp);
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException("City Access Delete_Company. Error al consumir el método. Detalle: " + ex.Message);
                }

                if (Respuesta_Del.Codigo.Equals("0"))
                    RespOk = true;
                else
                    throw new InvalidPluginExecutionException("City Access Delete_Company. Error al intentar borrar la Empresa. Detalle: " + Respuesta_Del.Descripcion.ToString());

            }
            
            return RespOk;
        }
        #endregion

        #region Método para Generar RollBack en CA de Inserción de Contacto
        public static bool EliminaCityAccGuest(string Mail, CityAccessWSSoapClient Cliente_CityAcc)
        {
            Resultado Respuesta_Del = null;
            bool RespOk = false;

            //BasicHttpBinding CityAccess_bin = new BasicHttpBinding();
            //CityAccess_bin.Name = "CityAccessWSSoap";
            //EndpointAddress EndPointCityAccess = new EndpointAddress("http://wshc.hotelescity.com:9742/CityHubV28Pruebas/CityAccessWS.asmx");

            //CityAccessWSSoapClient Cliente_CityAcc = new CityAccessWSSoapClient(CityAccess_bin, EndPointCityAccess);

            if (Mail != string.Empty)
            {
                try
                {
                    Respuesta_Del = Cliente_CityAcc.Delete_Guest(Mail, "");
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException("City Access Delete_Guest. Error al consumir el método. Detalle: " + ex.Message);
                }

                if (Respuesta_Del.Codigo.Equals("0"))
                    RespOk = true;
                else
                    throw new InvalidPluginExecutionException("City Access Delete_Guest. Error al intentar borrar el Contacto. Detalle: " + Respuesta_Del.Descripcion.ToString());

            }

            return RespOk;
        }
        #endregion

    }
}
